package errors

import (
    "errors"
    "fmt"
    "strings"
    "testing"
    "time"

    "kwdb-import/pkg/parser"
)

// TestNewError 测试基本错误创建
func TestNewError(t *testing.T) {
	err := NewError(ParseError, "test parse error")
	
	if err == nil {
		t.Fatal("NewError returned nil")
	}
	
	if err.Type != ParseError {
		t.Errorf("Expected error type %s, got %s", ParseError, err.Type)
	}
	
	if err.Message != "test parse error" {
		t.Errorf("Expected message 'test parse error', got %q", err.Message)
	}
	
	if err.Severity != SeverityMedium {
		t.Errorf("Expected default severity %s, got %s", SeverityMedium, err.Severity)
	}
	
	if err.Retryable {
		t.Error("Expected non-retryable error by default")
	}
	
	if err.Timestamp.IsZero() {
		t.Error("Expected timestamp to be set")
	}
	
	if err.StackTrace == "" {
		t.Error("Expected stack trace to be set")
	}
}

// TestNewErrorWithCause 测试带原因的错误创建
func TestNewErrorWithCause(t *testing.T) {
	cause := errors.New("original error")
	err := NewErrorWithCause(ExecutionError, "execution failed", cause)
	
	if err.Cause != cause {
		t.Errorf("Expected cause to be %v, got %v", cause, err.Cause)
	}
	
	if err.Unwrap() != cause {
		t.Errorf("Expected Unwrap() to return %v, got %v", cause, err.Unwrap())
	}
	
	errorMsg := err.Error()
	if !strings.Contains(errorMsg, "execution failed") {
		t.Errorf("Error message should contain 'execution failed', got: %s", errorMsg)
	}
	if !strings.Contains(errorMsg, "original error") {
		t.Errorf("Error message should contain cause, got: %s", errorMsg)
	}
}

// TestNewRetryableError 测试可重试错误创建
func TestNewRetryableError(t *testing.T) {
	err := NewRetryableError(ConnectionError, "connection timeout")
	
	if !err.Retryable {
		t.Error("Expected retryable error")
	}
	
	if !err.IsRetryable() {
		t.Error("IsRetryable() should return true")
	}
	
	if !IsRetryableError(err) {
		t.Error("IsRetryableError() should return true")
	}
}

// TestNewCriticalError 测试严重错误创建
func TestNewCriticalError(t *testing.T) {
	err := NewCriticalError(ConfigError, "critical config error")
	
	if err.Severity != SeverityCritical {
		t.Errorf("Expected severity %s, got %s", SeverityCritical, err.Severity)
	}
	
	if err.GetSeverity() != SeverityCritical {
		t.Errorf("GetSeverity() should return %s, got %s", SeverityCritical, err.GetSeverity())
	}
	
	if !IsCriticalError(err) {
		t.Error("IsCriticalError() should return true")
	}
}

// TestErrorWithContext 测试上下文信息
func TestErrorWithContext(t *testing.T) {
	err := NewError(ValidationError, "validation failed")
	err.WithContext("field", "username")
	err.WithContext("value", "invalid@user")
	
	context := err.GetContext()
	if len(context) != 2 {
		t.Errorf("Expected 2 context items, got %d", len(context))
	}
	
	if context["field"] != "username" {
		t.Errorf("Expected field 'username', got %v", context["field"])
	}
	
	if context["value"] != "invalid@user" {
		t.Errorf("Expected value 'invalid@user', got %v", context["value"])
	}
}

// TestErrorWithSuggestion 测试解决建议
func TestErrorWithSuggestion(t *testing.T) {
	err := NewError(FileError, "file not found")
	suggestion := "Please check the file path"
	err.WithSuggestion(suggestion)
	
	if err.GetSuggestion() != suggestion {
		t.Errorf("Expected suggestion %q, got %q", suggestion, err.GetSuggestion())
	}
}

// TestErrorWithErrorCode 测试错误代码
func TestErrorWithErrorCode(t *testing.T) {
	err := NewError(NetworkError, "network timeout")
	errorCode := "NET001"
	err.WithErrorCode(errorCode)
	
	if err.ErrorCode != errorCode {
		t.Errorf("Expected error code %q, got %q", errorCode, err.ErrorCode)
	}
}

// TestSpecificErrorCreators 测试具体错误创建函数
func TestSpecificErrorCreators(t *testing.T) {
	tests := []struct {
		name        string
		createFunc  func() *KWDBError
		expectedType ErrorType
		hasContext  bool
		hasSuggestion bool
	}{
		{
			name: "ParseError",
			createFunc: func() *KWDBError {
				return NewParseError("syntax error", 10, 5)
			},
			expectedType: ParseError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ParseErrorWithSQL",
			createFunc: func() *KWDBError {
				return NewParseErrorWithSQL("invalid SQL", "SELECT * FROM", parser.Other)
			},
			expectedType: ParseError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ConversionError",
			createFunc: func() *KWDBError {
				return NewConversionError("type mismatch", "VARCHAR", "INT")
			},
			expectedType: ConversionError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ConnectionError",
			createFunc: func() *KWDBError {
				return NewConnectionError("connection refused", "localhost", 5432)
			},
			expectedType: ConnectionError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ExecutionError",
			createFunc: func() *KWDBError {
				return NewExecutionError("query failed", "SELECT * FROM users")
			},
			expectedType: ExecutionError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ConfigError",
			createFunc: func() *KWDBError {
				return NewConfigError("invalid config", "database.host", "")
			},
			expectedType: ConfigError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "FileError",
			createFunc: func() *KWDBError {
				return NewFileError("file not found", "/path/to/file", "read")
			},
			expectedType: FileError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ValidationError",
			createFunc: func() *KWDBError {
				return NewValidationError("invalid value", "age", -1)
			},
			expectedType: ValidationError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "TimeoutError",
			createFunc: func() *KWDBError {
				return NewTimeoutError("operation timeout", 30*time.Second, "query")
			},
			expectedType: TimeoutError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "PermissionError",
			createFunc: func() *KWDBError {
				return NewPermissionError("access denied", "database", "write")
			},
			expectedType: PermissionError,
			hasContext: true,
			hasSuggestion: true,
		},
		{
			name: "ResourceError",
			createFunc: func() *KWDBError {
				return NewResourceError("memory limit exceeded", "memory", "1GB")
			},
			expectedType: ResourceError,
			hasContext: true,
			hasSuggestion: true,
		},
	}
	
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.createFunc()
			
			if err.Type != tt.expectedType {
				t.Errorf("Expected error type %s, got %s", tt.expectedType, err.Type)
			}
			
			if tt.hasContext && len(err.Context) == 0 {
				t.Error("Expected error to have context")
			}
			
			if tt.hasSuggestion && err.Suggestion == "" {
				t.Error("Expected error to have suggestion")
			}
		})
	}
}

// TestErrorTypeCheckers 测试错误类型检查函数
func TestErrorTypeCheckers(t *testing.T) {
	tests := []struct {
		name     string
		error    error
		checker  func(error) bool
		expected bool
	}{
		{
			name:     "IsParseError - true",
			error:    NewParseError("syntax error", 1, 1),
			checker:  IsParseError,
			expected: true,
		},
		{
			name:     "IsParseError - false",
			error:    NewConnectionError("connection failed", "localhost", 5432),
			checker:  IsParseError,
			expected: false,
		},
		{
			name:     "IsConversionError - true",
			error:    NewConversionError("type mismatch", "VARCHAR", "INT"),
			checker:  IsConversionError,
			expected: true,
		},
		{
			name:     "IsConnectionError - true",
			error:    NewConnectionError("connection failed", "localhost", 5432),
			checker:  IsConnectionError,
			expected: true,
		},
		{
			name:     "IsExecutionError - true",
			error:    NewExecutionError("query failed", "SELECT 1"),
			checker:  IsExecutionError,
			expected: true,
		},
		{
			name:     "IsRetryableError - true",
			error:    NewRetryableError(NetworkError, "network timeout"),
			checker:  IsRetryableError,
			expected: true,
		},
		{
			name:     "IsRetryableError - false",
			error:    NewError(ValidationError, "invalid input"),
			checker:  IsRetryableError,
			expected: false,
		},
		{
			name:     "IsCriticalError - true",
			error:    NewCriticalError(ConfigError, "critical config error"),
			checker:  IsCriticalError,
			expected: true,
		},
		{
			name:     "IsCriticalError - false",
			error:    NewError(ValidationError, "invalid input"),
			checker:  IsCriticalError,
			expected: false,
		},
	}
	
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := tt.checker(tt.error)
			if result != tt.expected {
				t.Errorf("Expected %v, got %v", tt.expected, result)
			}
		})
	}
}

// TestErrorStats 测试错误统计
func TestErrorStats(t *testing.T) {
	stats := NewErrorStats()
	
	if stats.TotalErrors != 0 {
		t.Errorf("Expected initial total errors to be 0, got %d", stats.TotalErrors)
	}
	
	if len(stats.ErrorsByType) != 0 {
		t.Errorf("Expected initial errors by type to be empty, got %d items", len(stats.ErrorsByType))
	}
	
	// 添加一些错误
	errors := []error{
		NewParseError("syntax error", 1, 1),
		NewConnectionError("connection failed", "localhost", 5432),
		NewParseError("another syntax error", 2, 3),
		NewCriticalError(ConfigError, "critical error"),
		NewRetryableError(NetworkError, "network timeout"),
	}
	
	for _, err := range errors {
		stats.AddError(err)
	}
	
	// 验证统计结果
	if stats.TotalErrors != 5 {
		t.Errorf("Expected total errors to be 5, got %d", stats.TotalErrors)
	}
	
	if stats.ErrorsByType[ParseError] != 2 {
		t.Errorf("Expected 2 parse errors, got %d", stats.ErrorsByType[ParseError])
	}
	
	if stats.ErrorsByType[ConnectionError] != 1 {
		t.Errorf("Expected 1 connection error, got %d", stats.ErrorsByType[ConnectionError])
	}
	
	if stats.CriticalErrors != 1 {
		t.Errorf("Expected 1 critical error, got %d", stats.CriticalErrors)
	}
	
	if stats.RetryableErrors != 2 { // ConnectionError 和 NetworkError 都是可重试的
		t.Errorf("Expected 2 retryable errors, got %d", stats.RetryableErrors)
	}
	
	// 测试最常见错误类型
	mostCommon := stats.GetMostCommonErrorType()
	if mostCommon != ParseError {
		t.Errorf("Expected most common error type to be %s, got %s", ParseError, mostCommon)
	}
	
	// 测试错误率
	time.Sleep(10 * time.Millisecond) // 确保有时间间隔
	errorRate := stats.GetErrorRate()
	if errorRate <= 0 {
		t.Errorf("Expected positive error rate, got %f", errorRate)
	}
	
	// 测试重置
	stats.Reset()
	if stats.TotalErrors != 0 {
		t.Errorf("Expected total errors to be 0 after reset, got %d", stats.TotalErrors)
	}
	if len(stats.ErrorsByType) != 0 {
		t.Errorf("Expected errors by type to be empty after reset, got %d items", len(stats.ErrorsByType))
	}
}

// TestErrorStatsWithStandardError 测试标准错误的统计
func TestErrorStatsWithStandardError(t *testing.T) {
	stats := NewErrorStats()
	standardErr := errors.New("standard error")
	
	stats.AddError(standardErr)
	
	if stats.TotalErrors != 1 {
		t.Errorf("Expected total errors to be 1, got %d", stats.TotalErrors)
	}
	
	if stats.ErrorsByType[UnknownError] != 1 {
		t.Errorf("Expected 1 unknown error, got %d", stats.ErrorsByType[UnknownError])
	}
	
	if stats.ErrorsBySeverity[SeverityMedium] != 1 {
		t.Errorf("Expected 1 medium severity error, got %d", stats.ErrorsBySeverity[SeverityMedium])
	}
}

// TestWrapError 测试错误包装
func TestWrapError(t *testing.T) {
	// 测试包装nil错误
	wrapped := WrapError(nil, ParseError, "test message")
	if wrapped != nil {
		t.Error("WrapError should return nil for nil error")
	}
	
	// 测试包装标准错误
	standardErr := errors.New("standard error")
	wrapped = WrapError(standardErr, ExecutionError, "execution failed")
	
	if wrapped == nil {
		t.Fatal("WrapError should not return nil for valid error")
	}
	
	if wrapped.Type != ExecutionError {
		t.Errorf("Expected error type %s, got %s", ExecutionError, wrapped.Type)
	}
	
	if wrapped.Message != "execution failed" {
		t.Errorf("Expected message 'execution failed', got %q", wrapped.Message)
	}
	
	if wrapped.Cause != standardErr {
		t.Errorf("Expected cause to be %v, got %v", standardErr, wrapped.Cause)
	}
	
	// 测试包装KWDBError（应该直接返回）
	kwdbErr := NewError(ValidationError, "validation error")
	wrapped = WrapError(kwdbErr, ParseError, "different message")
	
	if wrapped != kwdbErr {
		t.Error("WrapError should return the same KWDBError instance")
	}
}

// TestErrorIs 测试errors.Is兼容性
func TestErrorIs(t *testing.T) {
	parseErr1 := NewParseError("syntax error 1", 1, 1)
	parseErr2 := NewParseError("syntax error 2", 2, 2)
	connErr := NewConnectionError("connection failed", "localhost", 5432)
	
	// 测试相同类型的错误
	if !errors.Is(parseErr1, parseErr2) {
		t.Error("Parse errors should be considered equal with errors.Is")
	}
	
	// 测试不同类型的错误
	if errors.Is(parseErr1, connErr) {
		t.Error("Different error types should not be considered equal with errors.Is")
	}
	
	// 测试与标准错误
	standardErr := errors.New("standard error")
	if errors.Is(parseErr1, standardErr) {
		t.Error("KWDBError should not be equal to standard error with errors.Is")
	}
}

// TestFormatError 测试错误格式化
func TestFormatError(t *testing.T) {
	// 测试KWDBError格式化
	kwdbErr := NewParseError("syntax error", 10, 5)
	kwdbErr.WithSuggestion("Check your SQL syntax")
	kwdbErr.WithErrorCode("PARSE001")
	
	formatted := FormatError(kwdbErr)
	
	expectedParts := []string{
		"PARSE_ERROR",
		"syntax error",
		"时间:",
		"严重程度:",
		"上下文:",
		"line=10",
		"column=5",
		"建议: Check your SQL syntax",
	}
	
	for _, part := range expectedParts {
		if !strings.Contains(formatted, part) {
			t.Errorf("Formatted error should contain %q, got: %s", part, formatted)
		}
	}
	
	// 测试标准错误格式化
	standardErr := errors.New("standard error")
	formatted = FormatError(standardErr)
	
	if formatted != "standard error" {
		t.Errorf("Expected 'standard error', got %q", formatted)
	}
}

// TestGetErrorSuggestion 测试错误建议获取
func TestGetErrorSuggestion(t *testing.T) {
	tests := []struct {
		errorType ErrorType
		expected  string
	}{
		{ParseError, "请检查SQL语法是否正确"},
		{ConversionError, "请检查数据类型转换规则"},
		{ConnectionError, "请检查数据库服务状态"},
		{ExecutionError, "请检查SQL语句正确性"},
		{ConfigError, "请检查配置文件格式"},
		{FileError, "请检查文件路径"},
		{ValidationError, "请检查输入参数的格式"},
		{NetworkError, "请检查网络连接状态"},
		{TimeoutError, "请考虑增加超时时间"},
		{PermissionError, "请检查用户权限"},
		{ResourceError, "请检查系统资源使用情况"},
		{UnknownError, "请联系技术支持"},
		{ErrorType("INVALID_TYPE"), "请检查相关配置和环境设置"},
	}
	
	for _, tt := range tests {
		t.Run(string(tt.errorType), func(t *testing.T) {
			suggestion := GetErrorSuggestion(tt.errorType)
			if !strings.Contains(suggestion, strings.Split(tt.expected, "，")[0]) {
				t.Errorf("Expected suggestion to contain %q, got: %s", tt.expected, suggestion)
			}
		})
	}
}

// TestErrorChaining 测试错误链
func TestErrorChaining(t *testing.T) {
	// 创建错误链
	originalErr := errors.New("original error")
	middleErr := NewErrorWithCause(NetworkError, "network error", originalErr)
	topErr := NewErrorWithCause(ExecutionError, "execution failed", middleErr)
	
	// 测试错误链解包
	if !errors.Is(topErr, middleErr) {
		t.Error("Should be able to find middle error in chain")
	}
	
	// 使用errors.Unwrap逐层解包
	unwrapped := errors.Unwrap(topErr)
	if unwrapped != middleErr {
		t.Errorf("Expected unwrapped error to be middle error, got %v", unwrapped)
	}
	
	unwrapped = errors.Unwrap(unwrapped)
	if unwrapped != originalErr {
		t.Errorf("Expected unwrapped error to be original error, got %v", unwrapped)
	}
}

// TestConcurrentErrorStats 测试并发错误统计
func TestConcurrentErrorStats(t *testing.T) {
	stats := NewErrorStats()
	const numGoroutines = 100
	const errorsPerGoroutine = 10
	
	done := make(chan bool, numGoroutines)
	
	// 启动多个goroutine并发添加错误
	for i := 0; i < numGoroutines; i++ {
		go func(id int) {
			for j := 0; j < errorsPerGoroutine; j++ {
				err := NewParseError(fmt.Sprintf("error %d-%d", id, j), j, 1)
				stats.AddError(err)
			}
			done <- true
		}(i)
	}
	
	// 等待所有goroutine完成
	for i := 0; i < numGoroutines; i++ {
		<-done
	}
	
	// 验证统计结果
	expectedTotal := numGoroutines * errorsPerGoroutine
	if stats.TotalErrors != expectedTotal {
		t.Errorf("Expected total errors to be %d, got %d", expectedTotal, stats.TotalErrors)
	}
	
	if stats.ErrorsByType[ParseError] != expectedTotal {
		t.Errorf("Expected %d parse errors, got %d", expectedTotal, stats.ErrorsByType[ParseError])
	}
}

// BenchmarkErrorCreation 错误创建性能测试
func BenchmarkErrorCreation(b *testing.B) {
	b.Run("NewError", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = NewError(ParseError, "test error")
		}
	})
	
	b.Run("NewParseError", func(b *testing.B) {
		for i := 0; i < b.N; i++ {
			_ = NewParseError("syntax error", 10, 5)
		}
	})
	
	b.Run("NewErrorWithCause", func(b *testing.B) {
		cause := errors.New("cause")
		b.ResetTimer()
		for i := 0; i < b.N; i++ {
			_ = NewErrorWithCause(ExecutionError, "execution failed", cause)
		}
	})
}

// BenchmarkErrorFormatting 错误格式化性能测试
func BenchmarkErrorFormatting(b *testing.B) {
	err := NewParseError("syntax error", 10, 5)
	err.WithSuggestion("Check your SQL syntax")
	err.WithContext("file", "test.sql")
	
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = FormatError(err)
	}
}

// BenchmarkErrorStats 错误统计性能测试
func BenchmarkErrorStats(b *testing.B) {
	stats := NewErrorStats()
	err := NewParseError("syntax error", 1, 1)
	
	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		stats.AddError(err)
	}
}